//@author A0083782W
//All throw error code is contained inside:
#pragma once

#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <string>
#include "TECommonFunctions.h"
#include "ConstantList.h"

using std::string;
using std::cerr;
using std::endl;
using std::fstream;
using std::to_string;
using namespace GetCurrentTimeFunctions;
using TimeConstants::WEEKDAY_LIST;
using std::ios;

typedef const unsigned int ErrorID;
typedef const char* ErrorMessage;

static char const * const  ErrorLogFile = "D:\\TE_Error_Record.log";

enum class ThrowID {
	no_error = 0,
	WordList_Illegal_Time,
	WordList_Illegal_Date,

	//The duration has an end time that is earlier than start time.
	WordList_Illegal_Duration,

	WordList_Illegal_Repeat,
};

struct ERROR_STRUCT {
	ErrorID ID;
	ErrorMessage MESSAGE;
};

enum class ERR_ActionList {
	pop_error = 101,
	access_error,
};

enum class ERR_WordList {

};

enum class ERR_UserCommand {
	illegal_input_error = 301,
};

enum class ERR_Operations {
	unclear_command = 401,
	unknown_command,
	passing_empty_delete_array,
    passing_empty_modify_array,    
	passing_empty_mark_array,
	invalid_search_filter,
	newerror,
};

enum class ERR_IndexTranslator {
	repeatitive_array = 501,
};

enum class ERR_OutputDisplay {
	RepeatRule_ghost = 601,
};

static const ERROR_STRUCT ERROR_DATABASE[] = { 
	{(ErrorID)ERR_ActionList::pop_error, 
	"Try to pop when the ActionList class is empty"},
	{(ErrorID)ERR_ActionList::access_error,
	"Try to access a member that is outside the action stack"},

	{(ErrorID)ERR_UserCommand::illegal_input_error, 
	"Try to getInput when there is an error inside user input"},
	{(ErrorID)ERR_Operations::newerror,
	"new error"},
	{(ErrorID)ERR_Operations::unclear_command,
	"Try to pass an \'UNCLEAR\' command to Operations class in executeCommand() method"}, 
	{(ErrorID)ERR_Operations::passing_empty_delete_array,
	"The UserCommand passed an empty array for delete action inside Operations class"},
	{(ErrorID)ERR_Operations::passing_empty_modify_array,       
	"The UserCommand passed an empty array for modify action inside Operations class"},	
	{(ErrorID)ERR_Operations::unknown_command,
	"The UserCommand passed a value that is not inside the OperationType enum class"},
	{(ErrorID)ERR_Operations::invalid_search_filter,
	"The UserCommand passed a search struct contains an unknow search filter"},
	{(ErrorID)ERR_Operations::passing_empty_mark_array,       
	"The UserCommand passed an empty array for mark action inside Operations class"},
	{(ErrorID)ERR_IndexTranslator::repeatitive_array,
	"Deng Xuan, I thought you said that your search method will never pass a repetitive array-_-"},

	{(ErrorID)ERR_OutputDisplay::RepeatRule_ghost,
	"An unknown value of REPEAT_RULE enum class is present"},
};

static string timeString(con_str& mainString) {
	if (mainString.size() == 1) {
		return "0" + mainString;
	}
	else {
		return mainString;
	}
}

template<typename T>bool failProgram (T theFailedID) {
	const ErrorID nowID = (ErrorID)theFailedID;
	for (auto i:ERROR_DATABASE) {
		if (i.ID == nowID) {
			string myLine = "Error ";
			string myTime = "";
			myLine.append (to_string(i.ID));
			myLine.append ("  ");
			myLine.append (i.MESSAGE);
			myTime.append (timeString (to_string(getCurrentTime(TimeType::HOUR))) + ":");
			myTime.append (timeString (to_string(getCurrentTime(TimeType::MINUTE))) + ":");
			myTime.append (timeString (to_string(getCurrentTime(TimeType::SECOND))));
			myTime.append ("  ");
			myTime.append (timeString (to_string(getCurrentTime(TimeType::DAY)) + "/"));
			myTime.append (timeString (to_string(getCurrentTime(TimeType::MONTH)) + "/"));
			myTime.append (timeString (to_string(getCurrentTime(TimeType::HOUR))));
			myTime.append ("  ");
			myTime.append (WEEKDAY_LIST[getCurrentTime(TimeType::DAYOFWEEK)][0]);
			cerr << endl;
			cerr << myLine << endl;
			cerr << myTime << endl;
			fstream fp;
			fp.open(ErrorLogFile, ios::out|ios::app);
			fp << myLine << endl;
			fp << myTime << endl;
			fp << endl;
			fp.close();
			abort ();
			return true;
		}
	}
	return false;
}
